package com.example.demo.controller;

import com.example.demo.auth.Permission;
import com.example.demo.dto.ErrorCode;
import com.example.demo.dto.ResponseValue;
import com.example.demo.dto.common.ConsultantModel;
import com.example.demo.dto.common.SuperviseRecordModel;
import com.example.demo.dto.input.CommonInput;
import com.example.demo.entity.Consultant;
import com.example.demo.entity.Supervisor;
import com.example.demo.enums.Role;
import com.example.demo.exception.EntityAlreadyExistException;
import com.example.demo.exception.EntityNotExistException;
import com.example.demo.exception.IMIDHadCreatedException;
import com.example.demo.exception.IMIDNotExistException;
import com.example.demo.service.AliService;
import com.example.demo.service.ConsultantService;
import com.example.demo.service.IMService;
import com.example.demo.service.SupervisorService;
import com.example.demo.utils.IdGenerator;
import com.example.demo.utils.InputModelUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * 规定 supervisor 中 id 字段 为 "super_" + consultant_id;
 */

@RestController
@RequestMapping(value = "/supervisor")
public class SupervisorController {
    public final static String supervisorPrefix = "super_";

    private final SupervisorService supervisorService;
    private final ConsultantService consultantService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final AliService aliService;
    private final IMService imService;
    private final IdGenerator idGenerator;

    public SupervisorController(SupervisorService supervisorService,
                                ConsultantService consultantService,
                                RedisTemplate<String, Object> redisTemplate,
                                AliService aliService,
                                IMService imService,
                                IdGenerator idGenerator) {
        this.supervisorService = supervisorService;
        this.consultantService = consultantService;
        this.redisTemplate = redisTemplate;
        this.aliService = aliService;
        this.imService = imService;
        this.idGenerator = idGenerator;
    }

    //Permission(roles = {Role.ADMIN})
    @RequestMapping(method = RequestMethod.POST, value = "/admin/add")
    public ResponseValue<?> addSupervisorByAdmin(@RequestBody CommonInput input){
        Optional<CommonInput> optionalInput = Optional.of(input);
        String phone = optionalInput.map(CommonInput::getConsultant)
                .map(ConsultantModel::getPhoneNum)
                .orElse("");
        String password = optionalInput.map(CommonInput::getConsultant)
                .map(ConsultantModel::getPassword)
                .orElse("");

        String id = String.valueOf(idGenerator.nextId(Consultant.class));
        if (phone.equals("") || password.equals("")) {
            return ResponseValue.fail(ErrorCode.REQUEST_PARAM_ERROR);
        }

        Consultant consultant = InputModelUtil.transToConsultant(input.getConsultant());
        consultant.setId(id);
        consultant.setTotalMinutes(String.valueOf(0));
        consultant.setIsSupervisor("true");


        Supervisor supervisor = new Supervisor();
        supervisor.setId(supervisorPrefix + consultant.getId());
        supervisor.setConsultantId(consultant.getId());
        supervisor.setSuperviseTime(String.valueOf(0));
        supervisor.setSuperviseCount(String.valueOf(0));

        try {
            consultantService.addConsultant(consultant);
            supervisorService.addSupervisor(supervisor);
            String imId = imService.generateIMId(consultant.getId());
            String imSig = imService.getIMToken(consultant.getId());
            ConsultantModel model = InputModelUtil.transToModelOfSupervisor(consultant, supervisor);
            model.setImId(imId);
            model.setImSig(imSig);
            CommonInput output = new CommonInput();
            output.setConsultant(model);
            return ResponseValue.success(output);
        }catch (IOException | IMIDHadCreatedException | IMIDNotExistException e1){
            e1.printStackTrace();
            return ResponseValue.success(null);
        }catch (EntityAlreadyExistException e2) {
            return ResponseValue.fail(ErrorCode.ENTITY_ALREADY_EXIST);
        }
    }

    //Permission(roles = {Role.ADMIN})
    @RequestMapping(method = RequestMethod.POST, value = "/admin/delete")
    public ResponseValue<?> deleteSupervisorByAdmin(@RequestBody CommonInput input){
        Optional<CommonInput> optionalInput = Optional.of(input);
        String consultantId = optionalInput.map(CommonInput::getConsultant)
                                           .map(ConsultantModel::getId)
                                           .orElse("");

        String supervisorId = supervisorPrefix + consultantId;
        if (supervisorService.existSupervisor(supervisorId)) {
            consultantService.deleteConsultant(consultantId);
            supervisorService.deleteSupervisor(supervisorId);
            return ResponseValue.success(null);
        } else {
            return ResponseValue.fail(ErrorCode.ENTITY_NOT_EXIST);
        }
    }

    //Permission(roles = {Role.ADMIN})
    @RequestMapping(method = RequestMethod.POST, value = "/admin/update")
    public ResponseValue<?> updateSupervisorByAdmin(@RequestBody CommonInput input){
        Optional<CommonInput> optionalInput = Optional.of(input);
        // 这个 consultantId 实际上是 督导的 consultantId
        String consultantId = optionalInput.map(CommonInput::getGuide_record)
                                            .map(SuperviseRecordModel::getSupervisorId)
                                            .orElse("");

        int duration = Integer.parseInt( optionalInput.map(CommonInput::getGuide_record)
                                        .map(SuperviseRecordModel::getDuration)
                                        .orElse("0") );

        if (consultantId.equals("") || duration == 0) {
            return ResponseValue.fail(ErrorCode.PARAM_UNDEFINED);
        }

        String supervisorId = supervisorPrefix + consultantId;
        try {
            Supervisor supervisor = supervisorService.getSupervisor(supervisorId);
            int count = Integer.parseInt(supervisor.getSuperviseCount()) + 1;
            int time = Integer.parseInt(supervisor.getSuperviseTime()) + duration;
            supervisor.setSuperviseCount(String.valueOf(count));
            supervisor.setSuperviseTime(String.valueOf(time));
            supervisorService.updateSupervisor(supervisorId, supervisor);
            return ResponseValue.success(null);
        }catch (EntityNotExistException e) {
            return ResponseValue.fail(ErrorCode.ENTITY_NOT_EXIST);
        }
    }

    //Permission(roles = {Role.ADMIN})
    @RequestMapping(method = RequestMethod.POST, value = "/admin/get")
    public ResponseValue<?> getSupervisorByAdmin(@RequestBody CommonInput input){
        Optional<CommonInput> optionalInput = Optional.of(input);
        String consultantId = optionalInput.map(CommonInput::getConsultant)
                                            .map(ConsultantModel::getId)
                                            .orElse("");
        String supervisorId = supervisorPrefix + consultantId;

        try {
            Supervisor supervisor = supervisorService.getSupervisor(supervisorId);
            Consultant consultant = consultantService.getConsultant(consultantId);
            ConsultantModel model = InputModelUtil.transToModelOfSupervisor(consultant, supervisor);
            CommonInput output = new CommonInput();
            output.setConsultant(model);
            return ResponseValue.success(output);
        }catch (EntityNotExistException e) {
            return ResponseValue.fail(ErrorCode.ENTITY_NOT_EXIST);
        }
    }

    //Permission(roles = {Role.ADMIN})
    @RequestMapping(method = RequestMethod.POST, value = "/admin/getAll")
    public ResponseValue<?> getAllSupervisorByAdmin(){

        List<ConsultantModel> modelList = new ArrayList<>();
        List<Consultant> consultantParts = consultantService.getAllConsultantByIsSupervisor("true");
        for (Consultant consultant : consultantParts) {
            String supervisorId = supervisorPrefix + consultant.getId();
            try {
                Supervisor supervisor = supervisorService.getSupervisor(supervisorId);
                ConsultantModel model = InputModelUtil.transToModelOfSupervisor(consultant, supervisor);
                modelList.add(model);
            }catch (EntityNotExistException e) {
                return ResponseValue.fail(ErrorCode.ENTITY_NOT_EXIST);
            }
        }

        CommonInput output = new CommonInput();
        output.setConsultant_list(modelList);
        return ResponseValue.success(output);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/get")
    public ResponseValue<?> getSupervisor(@RequestBody CommonInput input){
        Optional<CommonInput> optionalInput = Optional.of(input);
        String consultantId = optionalInput.map(CommonInput::getConsultant)
                .map(ConsultantModel::getId)
                .orElse("");
        String supervisorId = supervisorPrefix + consultantId;

        try {
            Supervisor supervisor = supervisorService.getSupervisor(supervisorId);
            Consultant consultant = consultantService.getConsultant(consultantId);
            ConsultantModel model = InputModelUtil.transToModelOfSupervisor(consultant, supervisor);
            CommonInput output = new CommonInput();
            output.setConsultant(model);
            return ResponseValue.success(output);
        }catch (EntityNotExistException e) {
            return ResponseValue.fail(ErrorCode.ENTITY_NOT_EXIST);
        }
    }

    @RequestMapping(method = RequestMethod.POST, value = "/update")
    public ResponseValue<?> updateSupervisor(@RequestBody CommonInput input){
        Optional<CommonInput> optionalInput = Optional.of(input);
        // 这个 consultantId 实际上是 督导的 consultantId
        String consultantId = optionalInput.map(CommonInput::getGuide_record)
                .map(SuperviseRecordModel::getSupervisorId)
                .orElse("");

        int duration = Integer.parseInt( optionalInput.map(CommonInput::getGuide_record)
                .map(SuperviseRecordModel::getDuration)
                .orElse("0") );

        if (consultantId.equals("") || duration == 0) {
            return ResponseValue.fail(ErrorCode.PARAM_UNDEFINED);
        }

        String supervisorId = supervisorPrefix + consultantId;
        try {
            Supervisor supervisor = supervisorService.getSupervisor(supervisorId);
            int count = Integer.parseInt(supervisor.getSuperviseCount()) + 1;
            int time = Integer.parseInt(supervisor.getSuperviseTime()) + duration;
            supervisor.setSuperviseCount(String.valueOf(count));
            supervisor.setSuperviseTime(String.valueOf(time));
            supervisorService.updateSupervisor(supervisorId, supervisor);
            return ResponseValue.success(null);
        }catch (EntityNotExistException e) {
            return ResponseValue.fail(ErrorCode.ENTITY_NOT_EXIST);
        }
    }
}
